#include "precomp.h"

#include "Entity.h"

#include "Modules/EntityUnitStats.h"
#include "Modules/EntityMovement.h"
#include "Modules/EntityLogic.h"
#include "Modules/EntityBuilding.h"
#include "Modules/EntityDoodadd.h"
#include "Modules/EntityProjectile.h"

namespace Tmpl {

void Entity::Init(int id, int ownerId, int empireId, Vec2f pos, Vec2f facing, const UnitData& data)
{
	// Set basic stats
	mId = id;
	mOwnerId = ownerId;
	mEmpire = empireId;
	mStatus = Entity::ENTSTATUS_ALIVE;
	mDeathTimer = 0;
	mStats = -1;
	mMovement = -1;
	mLogic = -1;
	mMessages.clear();

	// Create Modules depending on unit
	mFlags = data.flags;
	if (IsDoodadd())
	{
		mStats = EntityDoodaddSystem::NewDoodadd(this, pos, data);
	}
	else if (IsHero())
	{
		mStats = EntityUnitStatSystem::NewStats(this, data);
		mMovement = EntityMovementSystem::NewMovement(this, pos, facing, data);
	}
	else if (IsUnit())
	{
		mStats = EntityUnitStatSystem::NewStats(this, data);
		mMovement = EntityMovementSystem::NewMovement(this, pos, facing, data);
		mLogic = EntityLogicSystem::NewLogic(this);
	}
	else if (IsBuilding())
	{
		mStats = EntityBuildingSystem::NewBuilding(this, pos, data);
	}
	else
	{
		Log::Write("Creating an entity with no unit type flag!");
	}
}

void Entity::Remove()
{
	//mMessages.clear();
	MsgArray().swap( mMessages );

	// Clear Modules
	if (mLogic > -1) EntityLogicSystem::RemoveLogic(mLogic);
	if (mMovement > -1) EntityMovementSystem::RemoveMovement(mMovement);
	if (mStats > -1) 
	{
		if (IsBuilding())
			EntityBuildingSystem::RemoveBuilding(mStats);
		else if (IsDoodadd())
			EntityDoodaddSystem::RemoveDoodadd(mStats);
		else
			EntityUnitStatSystem::RemoveStats(mStats);
	}

	// Clear Stats
	mId = -1;
	mStats = -1;
	mMovement = -1;
	mLogic = -1;

	mStatus = Entity::ENTSTATUS_REMOVED;
	mFlags = Entity::ENTITY_NONE;
	mDeathTimer = 0;
}

void Entity::Kill()
{
	if (mStatus == Entity::ENTSTATUS_ALIVE) 
	{
		mStatus = Entity::ENTSTATUS_REMOVE;
	}
}

// Render
void Entity::RenderLogic() const
{
	if (mLogic > -1) return EntityLogicSystem::GetLogic(mLogic)->Render();
}
// Stats
void Entity::SetTarget(int target)
{

}
float Entity::GetHPPercent() const
{
	if (mStats > -1) 
	{
		if (IsBuilding()) return EntityBuildingSystem::GetBuilding(mStats)->GetHPPercent();
		if (IsDoodadd()) return EntityDoodaddSystem::GetDoodadd(mStats)->GetHPPercent();
		return EntityUnitStatSystem::GetStats(mStats)->GetHPPercent();
	}
	return 0.0f;
}
float Entity::GetHPMax() const
{
	if (mStats > -1) 
	{
		if (IsBuilding()) return EntityBuildingSystem::GetBuilding(mStats)->GetHPMax();
		if (IsDoodadd()) return EntityDoodaddSystem::GetDoodadd(mStats)->GetHPMax();
		return EntityUnitStatSystem::GetStats(mStats)->GetHPMax();
	}
	return 0.0f;
}
float Entity::GetHP() const
{
	if (mStats > -1) 
	{
		if (IsBuilding()) return EntityBuildingSystem::GetBuilding(mStats)->GetHP();
		if (IsDoodadd()) return EntityDoodaddSystem::GetDoodadd(mStats)->GetHP();
		return EntityUnitStatSystem::GetStats(mStats)->GetHP();
	}
	return 0.0f;
}
// Movement
Vec2f Entity::GetPos() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetPos();
	if (mStats > -1)
	{
		if (IsBuilding()) return EntityBuildingSystem::GetBuilding(mStats)->GetPos();
		if (IsDoodadd()) return EntityDoodaddSystem::GetDoodadd(mStats)->GetPos();
	}
	return Vec2f();
}
Vec2f Entity::GetFacing() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetFacing();
	return Vec2f(1,0);
}
float Entity::GetSize() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetSize();
	if (mStats > -1)
	{
		if (IsBuilding()) return EntityBuildingSystem::GetBuilding(mStats)->GetCollisionSizeX()*0.5f;
		if (IsDoodadd()) return EntityDoodaddSystem::GetDoodadd(mStats)->GetSize();
	}
	return 0.0f;
}
float Entity::GetSpeed() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetSpeed();
	return 0.0f;
}
float Entity::GetMaxSpeed() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetMaxSpeed();
	return 0.0f;
}
Vec2f Entity::GetNextPos() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetNextPos();
	return Vec2f();
}
Vec2f Entity::GetNextFacing() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetNextFacing();
	return Vec2f(1,0);
}
float Entity::GetNextSize() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetNextSize();
	return 0.0f;
}
float Entity::GetNextSpeed() const
{
	if (mMovement > -1) return EntityMovementSystem::GetMovement(mMovement)->GetNextSpeed();
	return 0.0f;
}
void Entity::SetPos(Vec2f pos)
{
	if (mMovement > -1) EntityMovementSystem::GetMovement(mMovement)->SetPos(pos);
}
void Entity::SetFacing(Vec2f facing)
{
	if (mMovement > -1) EntityMovementSystem::GetMovement(mMovement)->SetFacing(facing);
}
void Entity::SetSize(float size)
{
	if (mMovement > -1) EntityMovementSystem::GetMovement(mMovement)->SetSize(size);
}
void Entity::SetSpeed(float speed)
{
	if (mMovement > -1) EntityMovementSystem::GetMovement(mMovement)->SetSpeed(speed);
}

// Messaging
MsgData* Entity::AddNewMessage()
{
	if (!IsAlive()) return 0;
	MsgData msg;
	mMessages.push_back(msg);
	return &mMessages.back();
}
void Entity::HandleAllMessages()
{
	while (!mMessages.empty())
	{
		MessageSystem::ProcessMessage(mMessages.front());
		mMessages.pop_front();
	}
}
void Entity::HandleMessage(const MsgData& msg)
{
	if (mLogic > -1) EntityLogicSystem::GetLogic(mLogic)->HandleMessage(msg);

	// Handle the messages on entity level
	switch (msg.msgType)
	{
	case MsgData::MSG_DAMAGE_DONE:
		float dmg = msg.damageDone.dmg;
		if (mStats > -1) 
		{
			if (IsBuilding()) EntityBuildingSystem::GetBuilding(mStats)->AddHP(-dmg, msg.damageDone.sender);
			else if (IsDoodadd()) EntityDoodaddSystem::GetDoodadd(mStats)->AddHP(-dmg, msg.damageDone.sender);
			else if (IsUnit()) EntityUnitStatSystem::GetStats(mStats)->AddHP(-dmg, msg.damageDone.sender);
		}
		break;
	}
}


} // Tmpl 